package stardust.product.platform.persistence.transaction;


import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import stardust.core.java.interceptor.Interceptor;
import stardust.core.java.interceptor.InterceptorProcessor;
import stardust.core.java.reflect.AnnotationReflect;
import stardust.product.platform.persistence.DataAccessFactory;
import stardust.product.platform.persistence.PersistenceException;


public class TransactionInterceptor implements Interceptor, MethodInterceptor
{
	
	public TransactionInterceptor()
	{
		;
	}
	
	public Object call(Object ivker, Object object, Method method, Object[] args) throws Throwable
	{
		DataAccessFactory dataAccessFactory;
		stardust.product.platform.persistence.transaction.Transaction transactionType;
		TransactionObject transactionObject;
		Object returnObject;
		
		dataAccessFactory = DataAccessFactory.getDataAccessFactory();
		if (dataAccessFactory == null)
		{
			throw new PersistenceException("DataAccessFactory只能在已绑定的数据访问上下文中执行。");
		}
		
		transactionType = method.getAnnotation(stardust.product.platform.persistence.transaction.Transaction.class);
		if (transactionType == null)
		{
			transactionType = AnnotationReflect.getAnnotation(method.getDeclaringClass(), stardust.product.platform.persistence.transaction.Transaction.class);
		}
		
		if (transactionType == null)
		{
			returnObject = method.invoke(object, args);
		}
		else
		{
			transactionObject = new TransactionObject
			(
				dataAccessFactory.getTransactionManager(), 
				new TransactionProperties(transactionType.type())
			);
			
			try
			{
				transactionObject.begin();
				
				if (ivker instanceof InterceptorProcessor)
				{
					returnObject = ((InterceptorProcessor) ivker).process();
				}
				else if (ivker instanceof MethodInvocation)
				{
					returnObject = ((MethodInvocation) ivker).proceed();
				}
				else
				{
					returnObject = method.invoke(object, args);
				}
				
				transactionObject.commit();
			}
			catch (Throwable e)
			{
				transactionObject.rollback();
				throw e;
			}
		}
		
		return returnObject;
	}
	
	public Object invoke(InterceptorProcessor processor) throws Throwable
	{
		return this.call(processor, processor.getObject(), processor.getMethod(), processor.getArgs());
		
	}

	public Object invoke(MethodInvocation methodinvocation) throws Throwable
	{
		return this.call(methodinvocation, methodinvocation.getThis(), methodinvocation.getMethod(), methodinvocation.getArguments());
	}
	
}